package com.mmg.cosplay.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.mmg.cosplay.entity.ChatMessages;
import com.mmg.cosplay.entity.po.RolePreset;
import com.mmg.cosplay.service.IConversationExportService;
import com.mmg.cosplay.service.IRolePresetService;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.ChatMessageDeserializer;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 会话导出服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ConversationExportServiceImpl implements IConversationExportService {

    private final MongoTemplate mongoTemplate;
    private final IRolePresetService rolePresetService;

    @Override
    public ResponseEntity<byte[]> exportToPdf(String memoryId) {
        try {
            // 获取会话数据
            ChatMessages chatMessages = getChatMessages(memoryId);
            if (chatMessages == null) {
                throw new RuntimeException("会话不存在或无权限访问");
            }

            // 获取角色信息
            RolePreset role = rolePresetService.getById(chatMessages.getRoleId());
            String roleName = role != null ? role.getRoleName() : "未知角色";

            // 解析消息
            List<ChatMessage> messages = ChatMessageDeserializer.messagesFromJson(chatMessages.getContent());

            // 创建PDF文档
            PDDocument document = new PDDocument();
            PDPage page = new PDPage();
            document.addPage(page);

            // 尝试加载中文字体
            PDFont font = loadChineseFont(document);
            PDFont boldFont = loadChineseFont(document); // 用于标题和发送者

            PDPageContentStream contentStream = new PDPageContentStream(document, page);

            // 定义颜色
            PDColor headerBgColor = new PDColor(new float[]{0.95f, 0.95f, 0.95f}, PDDeviceRGB.INSTANCE);
            PDColor userBgColor = new PDColor(new float[]{0.94f, 0.97f, 1.0f}, PDDeviceRGB.INSTANCE);
            PDColor aiBgColor = new PDColor(new float[]{0.97f, 0.94f, 1.0f}, PDDeviceRGB.INSTANCE);
            PDColor borderColor = new PDColor(new float[]{0.8f, 0.8f, 0.8f}, PDDeviceRGB.INSTANCE);
            PDColor textColor = new PDColor(new float[]{0.2f, 0.2f, 0.2f}, PDDeviceRGB.INSTANCE);

            float pageWidth = page.getMediaBox().getWidth();
            float pageHeight = page.getMediaBox().getHeight();
            float margin = 30; // 减小边距
            float contentWidth = pageWidth - 2 * margin;
            float yPosition = pageHeight - margin;

            // 绘制页面标题区域背景
            drawRectangle(contentStream, margin, yPosition - 70, contentWidth, 70, headerBgColor, borderColor);

            // 设置标题字体
            contentStream.setFont(boldFont, 16);
            contentStream.setNonStrokingColor(textColor);

            // 写入主标题
            yPosition -= 20;
            contentStream.beginText();
            contentStream.newLineAtOffset(margin + 15, yPosition);
            String title = "会话导出报告";
            contentStream.showText(filterTextForFont(title, boldFont));
            contentStream.endText();

            // 写入会话信息
            contentStream.setFont(font, 10);
            yPosition -= 18;
            contentStream.beginText();
            contentStream.newLineAtOffset(margin + 15, yPosition);
            String conversationTitle = "会话标题: " + (chatMessages.getTitle() != null ? chatMessages.getTitle() : "未命名会话");
            contentStream.showText(filterTextForFont(conversationTitle, font));
            contentStream.endText();

            yPosition -= 15;
            contentStream.beginText();
            contentStream.newLineAtOffset(margin + 15, yPosition);
            String roleText = "角色设定: " + roleName;
            contentStream.showText(filterTextForFont(roleText, font));
            contentStream.endText();

            yPosition -= 15;
            contentStream.beginText();
            contentStream.newLineAtOffset(margin + 15, yPosition);
            String timeText = "导出时间: " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"));
            contentStream.showText(filterTextForFont(timeText, font));
            contentStream.endText();

            yPosition -= 30;

            // 添加分隔线
            drawLine(contentStream, margin, yPosition, pageWidth - margin, yPosition, borderColor);
            yPosition -= 15;

            // 写入消息内容
            int messageIndex = 1;
            for (ChatMessage message : messages) {
                String sender = getMessageSender(message);
                String content = getMessageContent(message);

                // 使用新的文本换行方法
                String[] lines = wrapTextByWidth(filterTextForFont(content, font), font, 10, contentWidth - 60);
                float messageHeight = 35 + (lines.length * 14) + 15; // 优化高度计算

                // 检查是否需要新页面
                if (yPosition - messageHeight < margin + 30) {
                    contentStream.close();
                    page = new PDPage();
                    document.addPage(page);
                    contentStream = new PDPageContentStream(document, page);
                    yPosition = pageHeight - margin;
                }

                // 确定消息样式
                PDColor bgColor = message instanceof UserMessage ? userBgColor : aiBgColor;
                String senderLabel = message instanceof UserMessage ? "用户" : sender;

                // 绘制消息背景框
                float boxWidth = contentWidth - 20;
                float boxHeight = messageHeight - 5;
                drawRectangle(contentStream, margin + 10, yPosition - boxHeight, boxWidth, boxHeight, bgColor, borderColor);

                // 写入消息序号和发送者
                contentStream.setFont(boldFont, 11);
                contentStream.setNonStrokingColor(textColor);
                yPosition -= 20;
                contentStream.beginText();
                contentStream.newLineAtOffset(margin + 20, yPosition);
                String senderText = String.format("[%d] %s", messageIndex++, senderLabel);
                contentStream.showText(filterTextForFont(senderText, boldFont));
                contentStream.endText();

                // 写入消息内容
                contentStream.setFont(font, 10);
                yPosition -= 18;
                for (String line : lines) {
                    contentStream.beginText();
                    contentStream.newLineAtOffset(margin + 20, yPosition);
                    contentStream.showText(filterTextForFont(line, font));
                    contentStream.endText();
                    yPosition -= 14;
                }

                yPosition -= 15; // 消息间距
            }

            // 添加页脚
            yPosition = margin + 15;
            drawLine(contentStream, margin, yPosition, pageWidth - margin, yPosition, borderColor);

            contentStream.setFont(font, 9);
            yPosition -= 12;
            contentStream.beginText();
            contentStream.newLineAtOffset(margin, yPosition);
            String footerText = "导出完成 - " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss")) +
                    " | 共 " + messages.size() + " 条消息";
            contentStream.showText(filterTextForFont(footerText, font));
            contentStream.endText();

            contentStream.close();

            // 将PDF转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            document.save(outputStream);
            document.close();

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_PDF);
            headers.setContentDispositionFormData("attachment",
                    "conversation_" + memoryId + "_" + System.currentTimeMillis() + ".pdf");

            return ResponseEntity.ok()
                    .headers(headers)
                    .body(outputStream.toByteArray());

        } catch (Exception e) {
            log.error("导出PDF失败", e);
            throw new RuntimeException("导出PDF失败: " + e.getMessage());
        }
    }

    @Override
    public ResponseEntity<byte[]> exportToMarkdown(String memoryId) {
        try {
            ChatMessages chatMessages = getChatMessages(memoryId);
            if (chatMessages == null) {
                throw new RuntimeException("会话不存在或无权限访问");
            }

            RolePreset role = rolePresetService.getById(chatMessages.getRoleId());
            String roleName = role != null ? role.getRoleName() : "未知角色";

            List<ChatMessage> messages = ChatMessageDeserializer.messagesFromJson(chatMessages.getContent());

            StringBuilder markdown = new StringBuilder();
            markdown.append("# 会话导出报告\n\n");
            markdown.append("**会话标题**: ").append(chatMessages.getTitle() != null ? chatMessages.getTitle() : "未命名会话").append("\n\n");
            markdown.append("**角色设定**: ").append(roleName).append("\n\n");
            markdown.append("**导出时间**: ").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"))).append("\n\n");
            markdown.append("---\n\n");

            int messageIndex = 1;
            for (ChatMessage message : messages) {
                String sender = getMessageSender(message);
                String content = getMessageContent(message);
                String icon = getMessageIcon(message);

                markdown.append("## ").append(icon).append(" ").append(sender).append(" (").append(messageIndex++).append(")\n\n");
                markdown.append(escapeMarkdown(content)).append("\n\n");
                markdown.append("---\n\n");
            }

            markdown.append("*导出完成 - ").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss")))
                    .append(" | 共 ").append(messages.size()).append(" 条消息*");

            byte[] bytes = markdown.toString().getBytes(StandardCharsets.UTF_8);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.TEXT_MARKDOWN);
            headers.setContentDispositionFormData("attachment",
                    "conversation_" + memoryId + "_" + System.currentTimeMillis() + ".md");

            return ResponseEntity.ok()
                    .headers(headers)
                    .body(bytes);

        } catch (Exception e) {
            log.error("导出Markdown失败", e);
            throw new RuntimeException("导出Markdown失败: " + e.getMessage());
        }
    }

    /**
     * 获取会话消息
     */
    private ChatMessages getChatMessages(String memoryId) {
        try {
            // 检查用户登录状态
            if (!StpUtil.isLogin()) {
                log.error("用户未登录，无法导出会话: memoryId={}", memoryId);
                throw new RuntimeException("用户未登录，请先登录");
            }
            
            String userIdStr = StpUtil.getLoginIdAsString();
            Long userId = StpUtil.getLoginIdAsLong();
            log.info("正在查询会话: memoryId={}, userId={} ({})", memoryId, userId, userIdStr);
            
            // 首先检查会话是否存在（不考虑用户ID）
            Query existsQuery = new Query(Criteria.where("memoryId").is(memoryId));
            ChatMessages existingChat = mongoTemplate.findOne(existsQuery, ChatMessages.class);
            
            if (existingChat == null) {
                log.error("会话不存在: memoryId={}", memoryId);
                throw new RuntimeException("会话不存在");
            }
            
            log.info("找到会话: memoryId={}, 会话所属用户={}, 当前用户={}", 
                memoryId, existingChat.getUserId(), userId);
            
            // 检查会话是否属于当前用户（支持Long和String比较）
            boolean hasPermission = false;
            if (existingChat.getUserId() != null) {
                hasPermission = existingChat.getUserId().equals(userId) || 
                               existingChat.getUserId().toString().equals(userIdStr);
            }
            
            if (!hasPermission) {
                log.error("无权限访问会话: memoryId={}, 会话所属用户={}, 当前用户={}", 
                    memoryId, existingChat.getUserId(), userId);
                throw new RuntimeException("无权限访问该会话");
            }
            
            log.info("成功获取会话数据: memoryId={}, userId={}", memoryId, userId);
            return existingChat;
            
        } catch (Exception e) {
            log.error("获取会话消息失败: memoryId={}, error={}", memoryId, e.getMessage(), e);
            if (e.getMessage().contains("未登录") || e.getMessage().contains("会话不存在") || e.getMessage().contains("无权限")) {
                throw e; // 重新抛出具体的错误信息
            }
            throw new RuntimeException("会话不存在或无权限访问");
        }
    }

    /**
     * 获取消息发送者
     */
    private String getMessageSender(ChatMessage message) {
        if (message instanceof UserMessage) {
            return "用户";
        } else if (message instanceof AiMessage) {
            return "AI助手";
        } else if (message instanceof SystemMessage) {
            return "系统";
        } else {
            return "未知";
        }
    }

    /**
     * 获取消息图标
     */
    private String getMessageIcon(ChatMessage message) {
        if (message instanceof UserMessage) {
            return "👤";
        } else if (message instanceof AiMessage) {
            return "🤖";
        } else if (message instanceof SystemMessage) {
            return "⚙️";
        } else {
            return "❓";
        }
    }

    /**
     * 获取消息内容
     */
    private String getMessageContent(ChatMessage message) {
        if (message instanceof UserMessage) {
            return ((UserMessage) message).singleText();
        } else if (message instanceof AiMessage) {
            return ((AiMessage) message).text();
        } else if (message instanceof SystemMessage) {
            return ((SystemMessage) message).text();
        } else {
            return message.toString();
        }
    }

    /**
     * 根据实际文本宽度进行换行（适合中文）
     */
    private String[] wrapTextByWidth(String text, PDFont font, float fontSize, float maxWidth) throws IOException {
        if (text == null || text.isEmpty()) {
            return new String[]{""};
        }

        // 预处理文本，移除或替换不支持的字符
        text = preprocessTextForPdf(text);

        java.util.List<String> lines = new java.util.ArrayList<>();
        StringBuilder currentLine = new StringBuilder();
        
        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);
            String testLine = currentLine.toString() + ch;
            
            try {
                float textWidth = font.getStringWidth(testLine) / 1000 * fontSize;
                
                if (textWidth <= maxWidth) {
                    currentLine.append(ch);
                } else {
                    // 当前行已满，开始新行
                    if (currentLine.length() > 0) {
                        lines.add(currentLine.toString());
                        currentLine = new StringBuilder();
                        currentLine.append(ch);
                    } else {
                        // 单个字符就超宽，强制添加
                        lines.add(String.valueOf(ch));
                    }
                }
            } catch (Exception e) {
                // 如果字体不支持某个字符，使用字符数量换行作为备用
                return wrapText(preprocessTextForPdf(text), 50);
            }
        }
        
        if (currentLine.length() > 0) {
            lines.add(currentLine.toString());
        }
        
        return lines.toArray(new String[0]);
    }

    /**
     * 预处理PDF文本，移除或替换问题字符
     */
    private String preprocessTextForPdf(String text) {
        if (text == null) {
            return "";
        }
        
        return text
                .replace("\r\n", " ")  // Windows换行符
                .replace("\n", " ")    // Unix换行符
                .replace("\r", " ")    // Mac换行符
                .replace("\t", "    ") // 制表符替换为4个空格
                .replaceAll("\\p{Cntrl}", " "); // 移除其他控制字符
    }

    /**
     * 按字符数换行方法（优化版，适合中文）
     */
    private String[] wrapText(String text, int maxLength) {
        if (text == null || text.isEmpty()) {
            return new String[]{""};
        }

        if (text.length() <= maxLength) {
            return new String[]{text};
        }

        // 对于中文文本，按字符数量换行
        java.util.List<String> lines = new java.util.ArrayList<>();
        int start = 0;
        
        while (start < text.length()) {
            int end = Math.min(start + maxLength, text.length());
            
            // 尝试在合适的位置断行（避免在单词中间断开）
            if (end < text.length()) {
                // 查找最近的空格、标点符号或中文字符边界
                int breakPoint = findBestBreakPoint(text, start, end);
                if (breakPoint > start) {
                    end = breakPoint;
                }
            }
            
            lines.add(text.substring(start, end));
            start = end;
        }

        return lines.toArray(new String[0]);
    }

    /**
     * 寻找最佳断行点
     */
    private int findBestBreakPoint(String text, int start, int end) {
        // 从end向前查找合适的断行点
        for (int i = end - 1; i > start; i--) {
            char ch = text.charAt(i);
            // 在空格、标点符号或中文字符后断行
            if (ch == ' ' || ch == '，' || ch == '。' || ch == '！' || ch == '？' || 
                ch == '；' || ch == '：' || ch == '"' || ch == '"' || ch == '\n') {
                return i + 1;
            }
            // 中文字符可以在任意位置断行
            if (isChinese(ch)) {
                return i + 1;
            }
        }
        return end; // 如果找不到合适的断行点，使用原来的位置
    }

    /**
     * 判断是否为中文字符
     */
    private boolean isChinese(char ch) {
        return ch >= 0x4E00 && ch <= 0x9FFF;
    }

    /**
     * 转义Markdown特殊字符
     */
    private String escapeMarkdown(String text) {
        if (text == null) {
            return "";
        }
        return text.replace("\\", "\\\\")
                .replace("*", "\\*")
                .replace("_", "\\_")
                .replace("{", "\\{")
                .replace("}", "\\}")
                .replace("[", "\\[")
                .replace("]", "\\]")
                .replace("(", "\\(")
                .replace(")", "\\)")
                .replace("#", "\\#")
                .replace("+", "\\+")
                .replace("-", "\\-")
                .replace(".", "\\.")
                .replace("!", "\\!");
    }

    /**
     * 加载中文字体
     */
    private PDFont loadChineseFont(PDDocument document) {
        try {
            // 尝试加载系统字体（Windows）
            String[] systemFonts = {
                "C:/Windows/Fonts/simhei.ttf",    // 黑体
                "C:/Windows/Fonts/simsun.ttc",    // 宋体
                "C:/Windows/Fonts/msyh.ttc"       // 微软雅黑
            };
            
            for (String fontPath : systemFonts) {
                try {
                    java.io.File fontFile = new java.io.File(fontPath);
                    if (fontFile.exists()) {
                        return PDType0Font.load(document, fontFile);
                    }
                } catch (Exception e) {
                    log.debug("无法加载系统字体: " + fontPath, e);
                }
            }
            
            // 尝试从资源加载字体
            try (InputStream fontStream = getClass().getResourceAsStream("/fonts/NotoSansCJK-Regular.ttc")) {
                if (fontStream != null) {
                    return PDType0Font.load(document, fontStream);
                }
            } catch (Exception e) {
                log.debug("无法从资源加载中文字体", e);
            }
            
            log.warn("无法加载中文字体，使用默认字体");
            return new PDType1Font(Standard14Fonts.FontName.HELVETICA);
            
        } catch (Exception e) {
            log.error("字体加载失败，使用默认字体", e);
            return new PDType1Font(Standard14Fonts.FontName.HELVETICA);
        }
    }

    /**
     * 根据字体过滤文本
     */
    private String filterTextForFont(String text, PDFont font) {
        if (text == null) {
            return "";
        }
        
        StringBuilder result = new StringBuilder();
        for (char ch : text.toCharArray()) {
            try {
                // 尝试获取字符的字形宽度来检查字体是否支持该字符
                font.getStringWidth(String.valueOf(ch));
                result.append(ch);
            } catch (Exception e) {
                // 字体不支持该字符或出现其他错误，进行替换
                if (ch == '\n' || ch == '\r') {
                    result.append(" "); // 换行符替换为空格
                } else if (ch == '\t') {
                    result.append("    "); // 制表符替换为4个空格
                } else if (Character.isWhitespace(ch)) {
                    result.append(" "); // 其他空白字符替换为普通空格
                } else if (ch <= 127) {
                    result.append(ch); // 保留ASCII字符
                } else if (isChinese(ch)) {
                    result.append("[中文]"); // 中文字符替换为标记
                } else {
                    result.append("?"); // 其他字符替换为问号
                }
            }
        }
        return result.toString();
    }

    /**
     * 过滤不支持的字符
     */
    private String filterUnsupportedChars(String text) {
        if (text == null) {
            return "";
        }
        
        StringBuilder result = new StringBuilder();
        for (char ch : text.toCharArray()) {
            // 保留ASCII字符和常见符号
            if (ch <= 127 || Character.isWhitespace(ch)) {
                result.append(ch);
            } else if (isChinese(ch)) {
                result.append("?"); // 中文字符替换为问号
            } else {
                result.append("?"); // 其他特殊字符替换为问号
            }
        }
        return result.toString();
    }

    /**
     * 绘制矩形
     */
    private void drawRectangle(PDPageContentStream contentStream, float x, float y, float width, float height,
                               PDColor fillColor, PDColor strokeColor) throws IOException {
        // 绘制填充背景
        contentStream.setNonStrokingColor(fillColor);
        contentStream.addRect(x, y, width, height);
        contentStream.fill();

        // 绘制边框
        contentStream.setStrokingColor(strokeColor);
        contentStream.setLineWidth(0.5f);
        contentStream.addRect(x, y, width, height);
        contentStream.stroke();
    }

    /**
     * 绘制直线
     */
    private void drawLine(PDPageContentStream contentStream, float x1, float y1, float x2, float y2,
                          PDColor color) throws IOException {
        contentStream.setStrokingColor(color);
        contentStream.setLineWidth(1f);
        contentStream.moveTo(x1, y1);
        contentStream.lineTo(x2, y2);
        contentStream.stroke();
    }
}